﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using System.Windows.Forms;
using Leap;

namespace LeapInterface
{
    class LeapListener : Listener
    {

        private Object thisLock = new Object();
        private StringBuilder builder = new StringBuilder();
        public bool initialPosition = true;
        private int returnGestureN = 0;
        int limit1 = 200;
        int limit4 = 200;
        List<Finger> fi = new List<Finger>();

        private void SafeWriteLine(String line)
        {
            lock (thisLock)
            {
                Console.WriteLine(line);
            }
        }

        public override void OnInit(Controller controller)
        {
            SafeWriteLine("Initialized");
        }

        public override void OnConnect(Controller controller)
        {
            SafeWriteLine("Connected");

        }

        public override void OnDisconnect(Controller controller)
        {
            SafeWriteLine("Disconnected");
        }

        public override void OnExit(Controller controller)
        {
            SafeWriteLine("Exited");
        }


        private static int CompareSortFingers(Finger x, Finger y)
        {
            return x.TipPosition.x.CompareTo(y.TipPosition.x);
        }

        private void FindTwoFingersGesture(Controller controller, Hand hand)
        {
            Finger finger1 = hand.Fingers[0].Length > hand.Fingers[1].Length ? hand.Fingers[0] : hand.Fingers[1];
            Finger finger2 = hand.Fingers[0].Length < hand.Fingers[1].Length ? hand.Fingers[0] : hand.Fingers[1];
            Leap.Screen screen = controller.CalibratedScreens.ClosestScreenHit(finger1);

            if (!MyGlobals.oneFingerDetected)
            {
                Logger.OnPropertyChange(this, new DataEventArgs("Gained focus on 2 fingers"));
                MyGlobals.oneFingerDetected = true;
            }

            if (screen != null && screen.IsValid)
            {
                // Get the velocity of the finger tip
                var tipVelocity = (int)finger1.TipVelocity.Magnitude;
                MyGlobals.touchZoneValue = (-finger1.TouchDistance + 1) * 50;

                
                if (finger2.TipVelocity.Magnitude > 200 && tipVelocity < 120 && MyGlobals.mouseClicked == 0)
                {
                    
                    if (finger2.TipVelocity.y < -120)
                    {
                        
                        MouseCursor.LeftClick();
                       
                        MyGlobals.mouseClicked = 1;
                       
                    }

                    else if (finger2.TipVelocity.x > 50 && Math.Abs(finger2.TipPosition.x - finger1.TipPosition.x) < 40)
                    {
                        MouseCursor.LeftClick();
                        MouseCursor.LeftClick();
                        
                        MyGlobals.mouseClicked = 2;
                        
                    }

                    else if (finger2.TipVelocity.x < -150)
                    {
                        MouseCursor.RightClick();
                        MyGlobals.mouseClicked = 3;
                        
                    }

                    else if (finger2.TipVelocity.y > 120)
                    {
                        MouseCursor.LeftDown();
                        MyGlobals.mouseClicked = 4;
                       
                    }
 
                }

                if (MyGlobals.mouseClicked > 0)
                {
                    if (MyGlobals.mouseClicked == 1 || MyGlobals.mouseClicked == 2 || MyGlobals.mouseClicked == 3)
                    {
                        if (MyGlobals.SinceCliked++ == 20)
                        {
                            MyGlobals.mouseClicked = 0;
                            MyGlobals.SinceCliked = 0;
                        }
                    }
                    else if (MyGlobals.mouseClicked == 4)
                    {
                        if (finger2.TipVelocity.y < -60 && tipVelocity < 100 && MyGlobals.SinceCliked++ >= 20)
                        {
                            MouseCursor.LeftUp();
                            MyGlobals.mouseClicked = 0;
                            MyGlobals.SinceCliked = 0;
                        }
                    }
                }

             

                if (tipVelocity > 1)
                {

                    var xScreenIntersect = screen.Intersect(finger1, true, 4f).x;
                    var yScreenIntersect = screen.Intersect(finger1, true, 4f).y;


                    if (xScreenIntersect.ToString() != "NaN")
                    {

                        MyGlobals.mouseX = (int)(xScreenIntersect * screen.WidthPixels);
                        MyGlobals.mouseY = (int)(screen.HeightPixels - (yScreenIntersect * screen.HeightPixels));

                        MouseCursor.MoveCursor(MyGlobals.mouseX, MyGlobals.mouseY);
                    }
                }
            }
        }

        public int compareFingerLength(Finger finger1, Finger finger2)
        {
            return finger1.Length.CompareTo(finger2.Length);
        }
        
        private void FindThreeFingersGesture(Controller controller, Hand hand) 
        {
            Logger.OnPropertyChange(this, new DataEventArgs("Gained focus on 3 fingers"));
            

            List<Finger> list = new List<Finger>();

            for (int i = 0; i < 20; i++)
            {
                if(hand.Fingers[i].TipPosition.y != 0)
                list.Add(hand.Fingers[i]);
            }

            list.Sort(compareFingerLength);

            Leap.Screen screen = controller.CalibratedScreens.ClosestScreenHit(list[1]);

            if (Math.Abs(screen.Intersect(list[1], true, 4f).y - screen.Intersect(list[2], true, 4f).y) < 0.2)
            {
                
                if (screen.Intersect(list[1], true, 4f).y < 0.2)
                {
                    
                    if (screen.Intersect(list[1], true, 4f).y < -0.2)
                        MouseCursor.ScrollDown(100);
                    else MouseCursor.ScrollDown(40);
                }

                else if (screen.Intersect(list[1], true, 4f).y > 0.6)
                {
                    
                    if (screen.Intersect(list[1], true, 4f).y > 1.0)
                        MouseCursor.ScrollUp(100);
                    else MouseCursor.ScrollUp(40);
                }

                else if (screen.Intersect(list[1], true, 4f).x > 0.5)
                {  
                    MouseCursor.ScrollRight(40);
                }

                else if (screen.Intersect(list[1], true, 4f).x < 0.3)
                {
                  
                    MouseCursor.ScrollLeft(40);
                }
            }
        }

        private void wheelScroll(List<Finger> list, Controller controller)
        {
            Leap.Screen screen = controller.CalibratedScreens.ClosestScreenHit(list[1]);
            
            if (MyGlobals.wheelPos == 0)
            {
                MouseCursor.ScrollDown(40);
               
                if (screen.Intersect(list[1], true, 4f).y > 0.2)
                
                {
                    MyGlobals.wheelPos = -1;
                }
            }

            else if (MyGlobals.wheelPos == 1)
            {
                MouseCursor.ScrollUp(40);
                if (screen.Intersect(list[1], true, 4f).y < 0.6)
                {
                    MyGlobals.wheelPos = -1;
                }
            }

            else if (MyGlobals.wheelPos == 2)
            {
                MouseCursor.ScrollRight(20);
                if (list[1].TipVelocity.x < -220)
                {
                    MyGlobals.wheelPos = -1;
                }
            }

            else if (MyGlobals.wheelPos == 3)
            {
                MouseCursor.ScrollLeft(20);
                if (list[1].TipVelocity.x > 220)
                {
                    MyGlobals.wheelPos = -1;
                }
            }

            
        }

        private void FindFiveFingersGesture(Controller controller, List<Finger> fi, Hand hand, Frame frame)
        {

            for (int i = 0; i < 5; i++)
            {
                

                if (fi[i].TipVelocity.y < -200)
                {
                    MyGlobals.gestureSet[i] = true;
                    Keyboard.KeyPress(i);
                  
                    Logger.OnPropertyChange(this, new DataEventArgs("Done"));
                }
            }

               
                if (MyGlobals.debug)
                    Console.WriteLine(" id finger 1" + MyGlobals.gestureSet[0] + " 2 " + MyGlobals.gestureSet[1] + " 3 " + MyGlobals.gestureSet[2] + " 4 " + MyGlobals.gestureSet[3] + " 5 " + MyGlobals.gestureSet[4]);
            getBackMovement(controller, hand,fi);
           
              
            
        }
        
        private bool checkFingers(List<Finger> list)
        {
            int cmp = 0;

            for (int i = 0; i < 5; i++)
            {
                if(list[i].Direction.y > 0.07)
                    return false;

                if (list[i].Direction.y < -0.1)
                    cmp++;
            }

            if (cmp == 5)
                return false;

            return true;
        }


        private void getBackMovement(Controller controller, Hand hand, List<Finger> list)
        {


            for (int i = 0; i < 5; i++ )
            {
                
                if (list[i].TipVelocity.y > 60f)
                {

                   
                    Keyboard.KeyRelease(i);
                    MyGlobals.gestureSet[i] = false;
                    Logger.OnPropertyChange(this, new DataEventArgs("Done"));
                }
            }

            
        }


        private void FindAngularMovement(Hand hand, List<Finger> list)
        {
           
            double val = 0;
            for (int i = 0; i < 5; i++)
            {
                val = val + list[i].Direction.y;
            }
            val = val / 5;

            Console.WriteLine(" vit " + hand.PalmVelocity.y);

            
            if (hand.Direction.Pitch > 0.18 && val > 0.14)
            {
                if (MyGlobals.gestureSet[5] == false)
                {
                    MyGlobals.gestureSet[5] = true;
                    Logger.OnPropertyChange(this, new DataEventArgs("Done"));

                    Keyboard.KeyPress(5);
                }
            }

            
            else if (hand.Direction.Pitch < -0.20 && val < -0.28)
            {
                if (MyGlobals.gestureSet[6] == false)
                {
                    MyGlobals.gestureSet[6] = true;
                    Logger.OnPropertyChange(this, new DataEventArgs("Done"));
                   
                    Keyboard.KeyPress(6);

                }
            }

            else if (hand.PalmNormal.Yaw > 0.8 && Math.Abs(hand.PalmNormal.Pitch) - 1.30 < 0.50 && hand.PalmNormal.Roll > 0.3)
           
            {
                if (MyGlobals.gestureSet[7] == false)
                {
                    MyGlobals.gestureSet[7] = true;
                    Logger.OnPropertyChange(this, new DataEventArgs("Done"));

                    Keyboard.KeyPress(7);
                }

            }

         
            else if (hand.PalmNormal.Yaw < -1.1 && Math.Abs(hand.PalmNormal.Pitch) - 1.30 < 0.40 && hand.PalmNormal.Roll < -0.25)
         
            {
                if (MyGlobals.gestureSet[8] == false)
                {
                    MyGlobals.gestureSet[8] = true;
                    Logger.OnPropertyChange(this, new DataEventArgs("Done"));
                  
                    Keyboard.KeyPress(8);
                }
            }

            else
            {

                if (MyGlobals.gestureSet[6] == true)
                {
                    if (val < 0.1)
                    {
                        Keyboard.KeyRelease(6);
                        MyGlobals.gestureSet[6] = false;
                        Logger.OnPropertyChange(this, new DataEventArgs("Done"));
                    }
                }

                if (MyGlobals.gestureSet[5] == true)
                {
                    if (val > -0.1)
                    {
                        Keyboard.KeyRelease(5);
                        MyGlobals.gestureSet[5] = false;
                        Logger.OnPropertyChange(this, new DataEventArgs("Done"));
                    }
                }

                if (MyGlobals.gestureSet[7] == true)
                {
                    if (hand.PalmNormal.Yaw < 0.7)
                    {
                        Keyboard.KeyRelease(7);
                        MyGlobals.gestureSet[7] = false;
                        Logger.OnPropertyChange(this, new DataEventArgs("Done"));
                    }
                }

                if (MyGlobals.gestureSet[8] == true)
                {
                    if (hand.PalmNormal.Yaw > -0.9)
                    {
                        Keyboard.KeyRelease(8);
                        MyGlobals.gestureSet[8] = false;
                        Logger.OnPropertyChange(this, new DataEventArgs("Done"));
                    }
                }      
            }
        }

        public override void OnFrame(Controller controller)
        {
            System.Threading.Thread.Sleep(10);
           
            if (MyGlobals.fps == -1)
            {
                MyGlobals.stopwatch.Start();
                MyGlobals.fps = 0;
                Console.WriteLine(" clock started ");
            }
            if (MyGlobals.stopwatch.ElapsedMilliseconds > 1000)
            {
                if (MyGlobals.showFps)
                {
                    if(MyGlobals.debug)
                        Console.WriteLine("fps = " + MyGlobals.fps);

                    Logger.OnPropertyChange(this, new DataEventArgs("Fps"));
                }
                MyGlobals.fps = 0;
                MyGlobals.stopwatch.Restart();
            }
            MyGlobals.fps++;

            Frame frame = controller.Frame();
            
            
          
            if (frame.Hands.Empty)
            {
                Logger.OnPropertyChange(this, new DataEventArgs("Lost focus on 5 fingers"));
            }

            if (!frame.Hands.Empty)
            {
                
                
                // Get the first hand
                Hand hand = frame.Hands[0];

                // Check if the hand has any fingers
                FingerList fingers = hand.Fingers;

                
                

                if (hand.Pointables.Count >= 5)
                {
                    Logger.OnPropertyChange(this, new DataEventArgs("Gained focus on 5 fingers"));
                  

                    Frame f = controller.Frame();
                    // Get the frame that is 10 frame before the actual frame

                    fi.Clear();

                    for (int i = 0; i < 20; i++)
                    {
                        if (hand.Fingers[i].TipPosition.x != 0f)
                            fi.Add(hand.Fingers[i]);
                    }

                    fi.Sort(CompareSortFingers);

                    if(MyGlobals.PadMode)
                        FindFiveFingersGesture(controller, fi, hand, frame);

                    if (MyGlobals.DirectionnalArrowMode)
                    {
                        FindAngularMovement(hand, fi);
                    }
                }

                else if (hand.Pointables.Count == 2)
                {
                    if(MyGlobals.MouseMode)
                        FindTwoFingersGesture(controller, hand);
                }

                else if (hand.Pointables.Count == 3)
                {
                    
                    if (MyGlobals.MouseMode)
                        FindThreeFingersGesture(controller, hand);
                }

                else
                {
                    Logger.OnPropertyChange(this, new DataEventArgs("Lost focus on fingers"));
                }
            
            }
                 

        }

        public void OnFrame(Controller controller, Frame frame)
        {
            System.Threading.Thread.Sleep(10);
          
            if (MyGlobals.fps == -1)
            {
                MyGlobals.stopwatch.Start();
                MyGlobals.fps = 0;
                Console.WriteLine(" clock started ");
            }
            if (MyGlobals.stopwatch.ElapsedMilliseconds > 1000)
            {
                if (MyGlobals.showFps)
                {
                    if (MyGlobals.debug)
                        Console.WriteLine("fps = " + MyGlobals.fps);

                    Logger.OnPropertyChange(this, new DataEventArgs("Fps"));
                }
                MyGlobals.fps = 0;
                MyGlobals.stopwatch.Restart();
            }
            MyGlobals.fps++;

           
            if (frame.Hands.Empty)
            {
                Logger.OnPropertyChange(this, new DataEventArgs("Lost focus on 5 fingers"));
            }

            if (!frame.Hands.Empty)
            {
                
                
                // Get the first hand
                Hand hand = frame.Hands[0];

                //Console.WriteLine(" fingers : " + hand.Pointables.Count);

                // Check if the hand has any fingers
                FingerList fingers = hand.Fingers;

                
                

                if (hand.Pointables.Count >= 5)
                {
                    Logger.OnPropertyChange(this, new DataEventArgs("Gained focus on 5 fingers"));

                    Frame f = controller.Frame();

                    fi.Clear();

                    for (int i = 0; i < 20; i++)
                    {
                        if (hand.Fingers[i].TipPosition.x != 0f)
                            fi.Add(hand.Fingers[i]);
                    }

                    fi.Sort(CompareSortFingers);

                    if(MyGlobals.PadMode)
                        FindFiveFingersGesture(controller, fi, hand, frame);

                    if (MyGlobals.DirectionnalArrowMode)
                    {
                        FindAngularMovement(hand, fi);
                    }
                }

                else if (hand.Pointables.Count == 2)
                {
                    if(MyGlobals.MouseMode)
                        FindTwoFingersGesture(controller, hand);
                }

                else if (hand.Pointables.Count == 3)
                {
                    if (MyGlobals.MouseMode)
                        FindThreeFingersGesture(controller, hand);
                }

            }


            else
            {
                MyGlobals.disDiff = 0f;
                MyGlobals.SqzDiff = 0f;
                MyGlobals.rotDiff = 0f;

                Logger.OnPropertyChange(this, new DataEventArgs("Lost focus on fingers"));

            }
                 

        }

        
    }
}

